﻿using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using daStaticAnalyser.Analysers;
using daStaticAnalyser;
using daBase.Analyser;
using daSyntaxAnalyser.SyntaxTree;

namespace DifferentAnalizers
{
    /// <summary>
    /// Анализатор - наследование единого класса ошибки
    /// </summary>
    [AnalyserDefaultSettings("Наследование единого класса ошибки.", "Класс-ошибка \"выкидываемая\" пользователю не наследует единый класс ошибки{0}!", 40, "Все ошибки, которые \"выкидываются\" непосредственно пользователю, должны прямо или косвенно наследовать класс ошибки EApplicationException.")]
    public class EApplicationExceptionGenerationAnalyser : BaseStaticAnalyser
    {
        private List<string> generation;

        /// <summary>
        /// Задано ли имя класса-родителя
        /// </summary>
        [Category("Особые")]
        [DisplayName("Класс задан")]
        [Description("Если флаг не установлен, то имя промежуточного класса может быть любым.")]
        public bool IsSet { get { return (settings as EApplicationExceptionGenerationSettings).IsSet; } set { (settings as EApplicationExceptionGenerationSettings).IsSet = value; } }

        /// <summary>
        /// Имя класса-родителя
        /// </summary>
        [Category("Особые")]
        [DisplayName("Количество параметров")]
        [Description("Имя класса-родителя для всех ошибок.")]
        public string ClassName { get { return (settings as EApplicationExceptionGenerationSettings).ClassName; } set { (settings as EApplicationExceptionGenerationSettings).ClassName = value; } }

        protected override void Init()
        {
            if (settings == null)
                settings = new EApplicationExceptionGenerationSettings();
            (settings as EApplicationExceptionGenerationSettings).IsSet = true;
            (settings as EApplicationExceptionGenerationSettings).ClassName = "EApplicationException";
            base.Init();
        }

        /// <summary>
        /// Инициализация перед анализом
        /// </summary>
        public override void InitAnalysis()
        {
            generation.Clear();
            generation.Add((settings as EApplicationExceptionGenerationSettings).ClassName);
        }

        /// <summary>
        /// Сообщение об ошибке
        /// </summary>
        /// <returns>собственно, сообщение об ошибке</returns>
        protected override string ErrorMessage()
        {
            return string.Format(base.ErrorMessage(), ((settings as EApplicationExceptionGenerationSettings).IsSet) ? string.Format(" ({0})", (settings as EApplicationExceptionGenerationSettings).ClassName) : string.Empty);
        }

        /// <summary>
        /// Собственно анализ
        /// </summary>
        /// <param name="e">параметр анализа</param>
        protected override void DoAnalyse(SyntaxTreeArgs e)
        {
            if (e.Element is TypeDeclarationElement)
            {
                TypeDeclarationElement type = (e.Element as TypeDeclarationElement);
                if (type.Definition is ClassDefinitionElement)
                {
                    List<string> parents = new List<string>();
                    if (type.Definition is ClassOfDefinitionElement)
                        parents.Add((type.Definition as ClassOfDefinitionElement).Id.Id.Text.ToLower());
                    else if ((type.Definition is FullClassDefinitionElement) && ((type.Definition as FullClassDefinitionElement).Parents != null))
                        parents.AddRange((type.Definition as FullClassDefinitionElement).Parents.ConvertAll<string>((str)=>str.Id.Text.ToLower()));
                    foreach (string parent in parents)
                        if (generation.Contains(parent))
                            generation.Add(type.Id.Text.ToLower());
                }
            }
            else if (e.Element is RaiseStatementElement)
            {
                VariableExpressionElement variable = (e.Element as RaiseStatementElement).Error;
                if (variable is StandartVariableExpressionElement)
                {
                    string Id = string.Empty;
                    if ((variable as StandartVariableExpressionElement).Source != null)
                        foreach(SyntaxTreeElement element in (variable as StandartVariableExpressionElement).Source)
                            if (element is IdElement)
                            {
                                Id = element.ToString();
                                break;
                            }
                    if ((Id == string.Empty) && ((variable as StandartVariableExpressionElement).Parts.Count > 0))
                        Id = (variable as StandartVariableExpressionElement).Parts[0].Token.Text.ToLower();
                    if ((Id != string.Empty) && (!generation.Contains(Id)))
                        AddError(e.Element.StartInfo, e.Element.ToString());
                }
            }
        }

        /// <summary>
        /// Конструктор
        /// </summary>
        public EApplicationExceptionGenerationAnalyser()
            : base()
        {
            generation = new List<string>();
        }
    }
}
